package processbar

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"golang.org/x/sys/unix"
)

/***
前景 背景 颜色
---------------------------------------
30  40  黑色
31  41  红色
32  42  绿色
33  43  黄色
34  44  蓝色
35  45  紫红色
36  46  青蓝色
37  47  白色

代码 意义
-------------------------
 0  终端默认设置
 1  高亮显示
 4  使用下划线
 5  闪烁
 7  反白显示
 8  不可见
*/

const (
	//默认前景色
	Bar_Front_Color_Default = 30
	//前景黑色
	Bar_Front_Color_Black = 30
	//前景红色
	Bar_Front_Color_Red = 31
	//前景绿色
	Bar_Front_Color_Green = 32
	//前景黄色
	Bar_Front_Color_Yellow = 33
	//前景蓝色
	Bar_Front_Color_Blue = 34
	//前景紫红色
	Bar_Front_Color_PurpleRed = 35
	//前景青蓝色
	Bar_Front_Color_CyanineBlue = 36
	//前景白色
	Bar_Front_Color_White    = 37
	Show_Length_Mode_Default = 0 //原样
	Show_Length_Mode_MByte   = 1 //
)

//终端进度条
type Bar struct {
	current        int64
	total          int64
	percent        int
	rate           string
	color          int
	width          int
	startTime      time.Time
	lock           sync.RWMutex
	showLengthMode int
}

//
func NewBar(color, lengthMode int) *Bar {
	var width int = 20
	ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ)
	if err == nil {
		width = int(math.Max(float64(ws.Col-35), 10))
	}
	bar := &Bar{
		total:          100,
		current:        0,
		width:          width,
		color:          color,
		showLengthMode: lengthMode,
		startTime:      time.Now(),
	}
	return bar
}

//
func (b *Bar) display() {
	percent := float64(b.current) / float64(b.total)
	if iPercent := int(percent * 100); iPercent != b.percent {
		b.percent = iPercent
		b.rate = strings.Repeat("█", int(percent*float64(b.width)))
	}
	remain := time.Since(b.startTime).Seconds() / percent * (1 - percent)
	var currentValue, totalValue int64
	var label string
	if b.showLengthMode == Show_Length_Mode_Default {
		currentValue = b.current
		totalValue = b.total
		label = ""
	} else if b.showLengthMode == Show_Length_Mode_MByte {
		currentValue = b.current >> 20
		totalValue = b.total >> 20
		label = "MB"
	}
	fmt.Printf("\r\033[1;"+strconv.Itoa(b.color)+";48m[%-"+strconv.Itoa(b.width)+"s] %.0f%% %4d/%-4d%s 剩余:%4.0fs \033[0m ", b.rate, percent*100,
		currentValue, totalValue, label, remain)
}

//
func (b *Bar) Inc() {
	b.lock.Lock()
	defer b.lock.Unlock()
	b.current += 1
	if b.current > b.total {
		b.current = b.total
	}
	b.display()
}

//
func (b *Bar) Add(value int64) {
	b.lock.Lock()
	defer b.lock.Unlock()
	b.current += value
	if b.current > b.total {
		b.current = b.total
	}
	b.display()
}

//
func (b *Bar) Finish() {
	b.lock.Lock()
	defer b.lock.Unlock()
	b.current = 0
	b.total = 0
	b.percent = 0
	fmt.Println()
}

//
func (b *Bar) Reset(total, current int64) {
	b.lock.Lock()
	defer b.lock.Unlock()
	b.current = current
	b.total = total
	b.startTime = time.Now()
	b.display()
}

//实现io.writer接口
func (b *Bar) Write(p []byte) (n int, err error) {
	wl := len(p)
	b.Add(int64(wl))
	return wl, nil
}
